/*
 * OosProxy.java
 * 
 * Created on 08-sep-2007, 19:54:40
 */

package swagenda.proxy;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;
import java.util.TreeSet;

import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.abdera.Abdera;
import org.apache.abdera.model.Document;
import org.apache.abdera.model.Entry;
import org.apache.abdera.model.Feed;
import org.apache.abdera.model.Link;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;

import swagenda.data.Person;
import swagenda.data.Service;
import swagenda.data.Preferences;
import swagenda.exception.NotInitializedException;
import swagenda.ui.AlphaPanel;

public class OosProxy
{
	Logger logger = Logger.getLogger(this.getClass());

	private final String API_BASE_URL = "http://11870.com/api/v1";

	private final String APP_TOKEN = "swagenda-8389473487234";
	private final String SECRET = "13847554769";
	private String tempToken;
    
	public Preferences prefs;
	public Person owner = new Person();

	public void init() throws NotInitializedException
	{
		try
		{
			prefs = Preferences.load();
			loadPlaces(false);
		} catch(NotInitializedException e)
		{
			throw e;
		}
		catch(Exception e)
		{
			logger.error("can't initialize", e);
		}
	}
	public void reload()
	{
		try
		{
			loadPlaces(true);
			if (prefs==null) prefs = new Preferences();
			prefs.owner = this.owner;
			prefs.save();
		}
		catch(Exception e)
		{
			logger.error("can't reload", e);
		}
	}


	private TreeSet<Service> loadPlaces(boolean force) throws Exception
	{
		if (!force && prefs.ready())
			owner = prefs.owner;

		if (force || owner==null || owner.places == null || owner.places.size() == 0)
		{
			owner.places = downloadPlaces();
		}

		return owner.places;
	}

	public TreeSet<Service> getPlacesStartingWith(String start)
	{
		TreeSet<Service> auxPlaces = new TreeSet<Service>();
		if (start.equals(AlphaPanel.STRANGE))
		{
			for (Service p : owner.places)
			{
				boolean isAlpha = false;
				for (String alpha : AlphaPanel.ALPHA_ARRAY)
				{
					if (p.name.toLowerCase().startsWith(alpha))
					{
						isAlpha = true;
						break;
					}
				}
				if (!isAlpha)
					auxPlaces.add(p);
			}
		} else
		{
			for (Service p : owner.places)
			{
				if (p.name.toLowerCase().startsWith(start))
					auxPlaces.add(p);
			}
		}
		return auxPlaces;
	}

	public TreeSet<Service> downloadPlaces() throws Exception
	{
		TreeSet<Service> auxPlaces = new TreeSet<Service>();
		boolean next = true;
		String urlString = API_BASE_URL+"/sites/"+owner.slug;

		while (next)
		{
			HttpURLConnection c = makeConnection(urlString);
			c.connect();
			InputStream in = c.getInputStream();
			Document<Feed> doc = Abdera.getNewParser().parse(in, urlString);
			Feed feed = doc.getRoot();

			Link l = feed.getLink("next");

			for (Entry entry : feed.getEntries())
			{
				Service p = new Service(owner, entry);
				auxPlaces.add(p);
			}

			if (l == null)
			{
				next = false;
			} else
			{
				if (auxPlaces.size() > 1000)
				{
					// download no more, must stop somewhere to not overload the servers
					next = false;
				}
				urlString = l.getHref().toString();
			}
		}
		return auxPlaces;
	}
	
	private HttpURLConnection makeConnection(String urlString) throws Exception
	{
		URL url = new URL(urlString);
		HttpURLConnection c = (HttpURLConnection) url.openConnection();
		Base64 b64 = new Base64();
		String created = new Long(System.currentTimeMillis()).toString();
		String nonce = (new Long((new Random()).nextLong())).toString();

		String digest = new String(b64.encode(DigestUtils.sha(nonce + created + owner.authToken)));

		c.addRequestProperty("Authorization", "WSSE realm=\"11870.com\", profile=\"UsernameToken\"");
		c.addRequestProperty("X-WSSE", "UsernameToken Username=\"" + owner.email + "\", PasswordDigest=\"" + digest + "\", Nonce=\"" + nonce + "\", Created=\"" + created + "\"");

		c.setRequestMethod("GET");

		return c;
	}
	
	public String getTempToken() throws Exception
	{
		String authSign = DigestUtils.md5Hex(APP_TOKEN+SECRET);
		String urlString = "http://11870.com/manage-api/temp-token?appToken="+APP_TOKEN+"&authSign="+authSign;
		URL url = new URL(urlString);
		HttpURLConnection c = (HttpURLConnection) url.openConnection();
		c.connect();
		InputStream in = c.getInputStream();
		
		org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
		tempToken = doc.getDocumentElement().getTextContent();
		return tempToken;
	}
	
	public String getAuthToken() throws Exception
	{
		String urlString = "http://11870.com/manage-api/auth-token?tempToken="+tempToken;
		URL url = new URL(urlString);
		HttpURLConnection c = (HttpURLConnection) url.openConnection();
		c.connect();
		InputStream in = c.getInputStream();
		
		org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
		return doc.getDocumentElement().getTextContent();
	}
	
	@SuppressWarnings("unchecked")
	public void authenticate()
	{
		String url = "http://11870.com/manage-api/create-token?tempToken="+tempToken+"&privilege=WRITE";
		String osName = System.getProperty("os.name");

		try
		{
			if (osName.startsWith("Mac OS"))
			{
				Class fileMgr = Class.forName("com.apple.eio.FileManager");
				Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class });
				openURL.invoke(null, new Object[] { url });
			} else if (osName.startsWith("Windows"))
				Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
			else
			{ // assume Unix or Linux
				String[] browsers =	{ "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" };
				String browser = null;
				for (int count = 0; count < browsers.length && browser == null; count++)
					if (Runtime.getRuntime().exec(new String[] { "which", browsers[count] }).waitFor() == 0)
						browser = browsers[count];
				if (browser == null)
					throw new Exception("Could not find web browser");
				else
					Runtime.getRuntime().exec(new String[] { browser, url });
			}
		} catch (Exception e)
		{
			logger.error(e);
		}
	}
}
